/*
数据模型定义文件
包含云游戏压力测试客户端的所有数据结构、状态常量和请求响应模型
主要包括：
1. 客户端状态常量定义
2. 区域客户端管理器和客户端结构体
3. HTTP请求响应的数据结构
4. 压力测试任务参数结构体
5. CSV数据导出功能
*/
package service

import (
	"context"
	"encoding/csv"
	"fmt"
	"os"
	"sync"
	"time"

	"github.com/go-redis/redis/v8"
	"github.com/gorilla/websocket"
	"gitlab.vrviu.com/inviu/backend-go-public/gopublic/httpwrap"
	"gitlab.vrviu.com/inviu/backend-go-public/gopublic/vlog"
)

// 客户端状态常量定义
// 用于跟踪客户端在整个生命周期中的状态变化
const (
	REQ_UTOKEN_SUCC    = 1  // 请求用户Token成功
	REQ_UTOKEN_ERR     = -1 // 请求用户Token失败
	APPLY_UTOKEN_SUCC  = 2  // 申请用户Token成功
	APPLY_UTOKEN_FAIL  = -2 // 申请用户Token失败
	REQ_APPLY_SUCC     = 3  // 请求申请资源成功
	REQ_APPLY_ERR      = -3 // 请求申请资源失败
	APPLY_SUCC         = 4  // 申请资源成功
	ENter_UQ           = 5  // 进入排队状态
	Exit_UQ            = 6  // 退出排队状态
	APPLY_FAIL         = -4 // 申请资源失败
	WS_CONN_SUCC       = 7  // WebSocket连接成功
	WS_CONN_FAIL       = -7 // WebSocket连接失败
	LAUNCH_GAME_SENDED = 8  // 游戏启动请求已发送
	LAUNCH_GAME_SUCC   = 9  // 游戏启动成功
	LAUNCHGAME_FAIL    = -9 // 游戏启动失败
	ALLOC_PREPARE      = 10 // 资源分配准备中
	AREA_QING          = 11 // 区域清理中
	ALLOC_SUCC         = 12 // 资源分配成功
	GAMESTART_FAIL     = 13 // 游戏开始失败
	LAUNCHFALURE       = 14 // 启动失败
	READY_RENDER       = 15 // 准备渲染
	ForceQuit          = 16 // 强制退出
	CURRENT_LIMITING   = -5 // 当前限流中
	IS_QUEUE           = 17 // 正在排队
	NO_QUEUE           = 18 // 无需排队
	EXIt_UQ_FORCE      = 19 // 强制退出排队
)

// StatusToString 状态码转换为可读字符串
// 将数字状态码转换为对应的中文描述
func StatusToString(status int) string {
	statusMap := map[int]string{
		REQ_UTOKEN_SUCC:    "请求用户Token成功",
		REQ_UTOKEN_ERR:     "请求用户Token失败",
		APPLY_UTOKEN_SUCC:  "申请用户Token成功",
		APPLY_UTOKEN_FAIL:  "申请用户Token失败",
		REQ_APPLY_SUCC:     "请求申请资源成功",
		REQ_APPLY_ERR:      "请求申请资源失败",
		APPLY_SUCC:         "申请资源成功",
		ENter_UQ:           "进入排队状态",
		Exit_UQ:            "退出排队状态",
		APPLY_FAIL:         "申请资源失败",
		WS_CONN_SUCC:       "WebSocket连接成功",
		WS_CONN_FAIL:       "WebSocket连接失败",
		LAUNCH_GAME_SENDED: "游戏启动请求已发送",
		LAUNCH_GAME_SUCC:   "游戏启动成功",
		LAUNCHGAME_FAIL:    "游戏启动失败",
		ALLOC_PREPARE:      "资源分配准备中",
		AREA_QING:          "区域清理中",
		ALLOC_SUCC:         "资源分配成功",
		GAMESTART_FAIL:     "游戏开始失败",
		LAUNCHFALURE:       "启动失败",
		READY_RENDER:       "准备渲染",
		ForceQuit:          "强制退出",
		CURRENT_LIMITING:   "当前限流中",
		IS_QUEUE:           "正在排队",
		NO_QUEUE:           "无需排队",
		EXIt_UQ_FORCE:      "强制退出排队",
	}

	if desc, ok := statusMap[status]; ok {
		return desc
	}
	return fmt.Sprintf("未知状态:%d", status)
}

// CSVRecord CSV记录结构体
// 用于存储要写入CSV文件的数据
type CSVRecord struct {
	Uid        uint64    // 用户ID
	FlowID     string    // 流程ID
	Vmid       uint64    // 虚拟机ID
	Status     int       // 状态码
	StatusDesc string    // 状态描述
	Timestamp  time.Time // 记录时间戳
}

// CSVManager CSV文件管理器
// 管理CSV文件的创建、写入和关闭
type CSVManager struct {
	filename string
	file     *os.File
	writer   *csv.Writer
	mutex    sync.Mutex
}

// csvManager 全局CSV管理器实例
var csvManager *CSVManager
var csvOnce sync.Once

// GetCSVManager 获取CSV管理器单例
// 确保每次压测只创建一个CSV文件
func GetCSVManager() *CSVManager {
	csvOnce.Do(func() {
		csvManager = NewCSVManager()
	})
	return csvManager
}

// NewCSVManager 创建新的CSV管理器
// 在logs目录下创建以时间戳命名的CSV文件，支持Excel UTF-8兼容性
func NewCSVManager() *CSVManager {
	timestamp := time.Now().Format("20060102_150405")
	filename := fmt.Sprintf("logs/stress_test_%s.csv", timestamp)

	// 确保logs目录存在
	if err := os.MkdirAll("logs", 0755); err != nil {
		vlog.Errorf("Failed to create logs directory: %v", err)
		return nil
	}

	// 创建CSV文件
	file, err := os.Create(filename)
	if err != nil {
		vlog.Errorf("Failed to create CSV file %s: %v", filename, err)
		return nil
	}

	// 写入UTF-8 BOM标记，确保Excel正确识别编码
	// BOM: EF BB BF
	if _, err := file.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil {
		vlog.Errorf("Failed to write BOM to CSV file: %v", err)
		file.Close()
		return nil
	}

	writer := csv.NewWriter(file)

	// 写入CSV头部
	header := []string{"用户ID", "流程ID", "虚拟机ID", "状态码", "状态描述", "记录时间"}
	if err := writer.Write(header); err != nil {
		vlog.Errorf("Failed to write CSV header: %v", err)
		file.Close()
		return nil
	}
	writer.Flush()

	vlog.Infof("Created CSV file: %s", filename)

	return &CSVManager{
		filename: filename,
		file:     file,
		writer:   writer,
	}
}

// shouldWriteToCSV 判断是否应该写入CSV文件
// 只有特定的状态码才需要记录到CSV文件中
func shouldWriteToCSV(status int) bool {
	// 定义需要记录的状态码列表
	recordableStatuses := map[int]bool{
		REQ_UTOKEN_ERR:    true, // -1: 请求用户Token失败
		APPLY_UTOKEN_FAIL: true, // -2: 申请用户Token失败
		REQ_APPLY_ERR:     true, // -3: 请求申请资源失败
		APPLY_FAIL:        true, // -4: 申请资源失败
		CURRENT_LIMITING:  true, // -5: 当前限流中
		WS_CONN_FAIL:      true, // -7: WebSocket连接失败
		LAUNCHGAME_FAIL:   true, // -9: 游戏启动失败
		ALLOC_SUCC:        true, // 12: 资源分配成功
		GAMESTART_FAIL:    true, // 13: 游戏开始失败
		LAUNCHFALURE:      true, // 14: 启动失败
		EXIt_UQ_FORCE:     true, // 19: 强制退出排队
	}

	return recordableStatuses[status]
}

// WriteRecord 写入CSV记录
// 线程安全地写入一条记录到CSV文件
func (cm *CSVManager) WriteRecord(record CSVRecord) error {
	if cm == nil {
		return fmt.Errorf("CSV manager not initialized")
	}

	cm.mutex.Lock()
	defer cm.mutex.Unlock()

	// 准备要写入的数据行
	row := []string{
		fmt.Sprintf("%d", record.Uid),
		record.FlowID,
		fmt.Sprintf("%d", record.Vmid),
		fmt.Sprintf("%d", record.Status),
		record.StatusDesc,
		record.Timestamp.Format("2006-01-02 15:04:05"),
	}

	// 写入CSV
	if err := cm.writer.Write(row); err != nil {
		vlog.Errorf("Failed to write CSV record: %v", err)
		return err
	}

	cm.writer.Flush()

	// 检查写入是否有错误
	if err := cm.writer.Error(); err != nil {
		vlog.Errorf("CSV writer error: %v", err)
		return err
	}

	return nil
}

// Close 关闭CSV文件
// 确保所有数据都已写入磁盘
func (cm *CSVManager) Close() {
	if cm == nil {
		return
	}

	cm.mutex.Lock()
	defer cm.mutex.Unlock()

	if cm.writer != nil {
		cm.writer.Flush()
		cm.writer = nil
	}

	if cm.file != nil {
		cm.file.Close()
		cm.file = nil
		vlog.Infof("Closed CSV file: %s", cm.filename)
	}
}

// ResetCSVManager 重置CSV管理器
// 用于新的压测任务开始时重新创建CSV文件
func ResetCSVManager() {
	if csvManager != nil {
		csvManager.Close()
	}
	csvManager = nil
	csvOnce = sync.Once{}
}

// AreaClientMgr 区域客户端管理器
// 管理多个AreaClient实例，用于批量压力测试
type AreaClientMgr struct {
	AreaClients []*AreaClient // 客户端实例列表
	Result_key  string        // Redis中存储结果的键名
}

// ClientController 客户端控制器
// 控制客户端行为和测试参数
type ClientController struct {
	IsStreaming    bool   `json:"is_streaming"`     // 是否启用流式传输
	IsQuickOut     bool   `json:"is_quick_out"`     // 是否快速退出
	IsAutoResist   bool   `json:"is_auto_resist"`   // 是否自动重试
	DelayExit      int    `json:"delay_exit"`       // 延迟退出时间(秒)
	RsetID         int    `json:"rset_id"`          // 资源集ID
	IsAutoRegister bool   `json:"is_auto_register"` // 是否自动注册
	TaskID         string `json:"task_id"`          // 任务ID
	IsTrylock      bool   `json:"is_trylock"`       // 是否启用资源预锁定
}

// AreaClient 区域客户端
// 代表单个虚拟用户客户端，包含完整的生命周期状态
type AreaClient struct {
	Uid              uint64                // 用户唯一ID
	AreaType         int                   // 区域类型
	Atoken           string                // 区域访问Token
	Utoken           string                // 用户Token
	DevID            string                // 设备ID
	Gid              uint64                // 游戏ID
	bizType          uint64                // 业务类型
	FlowID           string                // 流ID，用于跟踪单个客户端
	AreaAddr         string                // 区域服务地址
	UServoAddr       string                // 用户服务地址
	UAccessAddr      string                // 访问服务地址
	UserID           string                // 用户ID（字符串形式）
	DevType          int                   // 设备类型
	WSConn           *websocket.Conn       // WebSocket连接
	HBSigCh          chan bool             // 心跳信号通道
	StartTime        time.Time             // 开始时间
	HoldTime         int                   // 保持时间（秒）
	ClientExit       bool                  // 客户端是否退出
	AllocState       bool                  // 分配状态
	AllocTime        time.Time             // 分配时间
	QueueState       bool                  // 排队状态
	QueueTime        time.Time             // 排队时间
	PreAllocTime     time.Time             // 预分配时间
	status           int                   // 当前状态
	fail_msg         error                 // 失败消息
	redisCli         redis.UniversalClient // Redis客户端
	Result_key       string                // 结果存储键
	RelaunchDuration int                   // 重启间隔时间
	RelaunchTimes    int                   // 重启次数
	wg               *sync.WaitGroup       // 同步等待组
	ClientController *ClientController     // 客户端控制器
}

// WriteToCSV 将客户端数据写入CSV文件
// 只有特定状态码才会写入CSV文件
// 参数:
//
//	vmid: 虚拟机ID，如果为0则表示未分配
func (client *AreaClient) WriteToCSV(vmid uint64) {
	// 检查是否需要写入CSV
	if !shouldWriteToCSV(client.status) {
		return
	}

	csvManager := GetCSVManager()
	if csvManager == nil {
		vlog.Errorf("CSV manager not available for client %d", client.Uid)
		return
	}

	record := CSVRecord{
		Uid:        client.Uid,
		FlowID:     client.FlowID,
		Vmid:       vmid,
		Status:     client.status,
		StatusDesc: StatusToString(client.status),
		Timestamp:  time.Now(),
	}

	if err := csvManager.WriteRecord(record); err != nil {
		vlog.Errorf("Failed to write CSV record for client %d: %v", client.Uid, err)
	} else {
		vlog.Infof("[CSV] Recorded client %d, FlowID: %s, Vmid: %d, Status: %s",
			client.Uid, client.FlowID, vmid, StatusToString(client.status))
	}
}

// AreaClientInfo 区域客户端信息
// 用于序列化存储到Redis的客户端状态信息
type AreaClientInfo struct {
	Uid         uint64  `json:"uid"`          // 用户ID
	bizType     uint64  `json:"biz_type"`     // 业务类型
	AreaType    int     `json:"area_type"`    // 区域类型
	Atoken      string  `json:"atoken"`       // 区域Token
	Utoken      string  `json:"utoken"`       // 用户Token
	DevID       string  `json:"dev_id"`       // 设备ID
	Gid         uint64  `json:"gid"`          // 游戏ID
	FlowID      string  `json:"flow_id"`      // 流ID
	AreaAddr    string  `json:"area_addr"`    // 区域地址
	UServoAddr  string  `json:"uservo_addr"`  // 用户服务地址
	UAccessAddr string  `json:"uaccess_addr"` // 访问地址
	UserID      string  `json:"user_id"`      // 用户ID
	DevType     int     `json:"dev_type"`     // 设备类型
	Status      int     `json:"status"`       // 状态
	Fail_msg    string  `json:"fail_msg"`     // 失败消息
	Is_done     int     `json:"is_done"`      // 是否完成
	AllocTime   float64 `json:"alloc_time"`   // 分配耗时
}

// TokenInfo token信息结构体
// 用户Token相关信息
type TokenInfo struct {
	Token     string `json:"token"`      // Token值
	AppUserID string `json:"app_userid"` // 应用用户ID
	UserID    string `json:"userid"`     // 用户ID
	//ExpireTime time.Time `json:"expire_time"` // Token过期时间（已注释）
}

// TokenResult token获取结果
// API返回的Token信息
type TokenResult struct {
	Head httpwrap.HTTPCommonHead `json:"ret"`        // 通用HTTP响应头
	Info TokenInfo               `json:"token_info"` // Token信息
}

// CallbackResult 回调结果
// 任务完成后的回调响应
type CallbackResult struct {
	Head httpwrap.HTTPCommonHead `json:"ret"`  // 通用HTTP响应头
	Body CallbackBody            `json:"body"` // 回调内容
}

// CallbackBody 回调返回信息
// 回调请求的具体内容
type CallbackBody struct {
	TaskID string `json:"task_id"` // 任务ID
}

// AccessInfo 接入信息
// 游戏服务接入的网络信息
type AccessInfo struct {
	AccessAddr string `json:"access_ipv4_address"` // IPv4访问地址
	AccessPort int    `json:"access_ipv4_port"`    // IPv4访问端口
}

// QueueInfo 排队信息
// 用户排队相关的详细信息
type QueueInfo struct {
	Addr        string `json:"address"`      // 排队服务地址
	Port        uint16 `json:"port"`         // 排队服务端口
	Rank        int64  `json:"rank"`         // 当前排队位置
	Total       int64  `json:"total"`        // 总排队人数
	SessionID   string `json:"session_id"`   // 排队会话ID
	Ewtime      int    `json:"ewtime"`       // 预计等待时间
	SegInterval int64  `json:"seg_interval"` // 查询间隔时间
}

// AreaInfo 区域信息
// 区域申请成功后返回的详细信息
type AreaInfo struct {
	FlowID string     `json:"flow_id"`     // 流程ID
	Token  string     `json:"token"`       // 区域Token
	UUID   uint64     `json:"uuid"`        // 用户UUID
	UGID   uint64     `json:"ugid"`        // 用户组ID
	UID    uint64     `json:"uid"`         // 用户ID
	GID    uint64     `json:"gid"`         // 游戏ID
	Info   AccessInfo `json:"access_info"` // 接入信息
	QInfo  QueueInfo  `json:"queue_info"`  // 排队信息
}

// AreaResult 申请区域结果
// 区域申请API的响应结构
type AreaResult struct {
	Head httpwrap.HTTPCommonHead `json:"ret"`  // 通用HTTP响应头
	Info AreaInfo                `json:"body"` // 区域信息
}

// UnionRankInfo 联合排队信息
// 联合排队服务返回的排队状态信息
type UnionRankInfo struct {
	RankTs      int64  `json:"rank_ts"`      // 排队时间戳
	Rank        int64  `json:"rank"`         // 当前排队位置
	Total       int64  `json:"total"`        // 总排队人数
	QueueFlag   int64  `json:"queue_flag"`   // 排队标志（0:继续排队，1:出队）
	SegInterval int64  `json:"seg_interval"` // 查询间隔时间
	FlowID      string `json:"flow_id"`      // 流程ID
	Ewtime      int    `json:"ewtime"`       // 预计等待时间
}

// UnionRankResult 联合排队结果
// 排队查询API的响应结构
type UnionRankResult struct {
	Head httpwrap.HTTPCommonHead `json:"ret"`  // 通用HTTP响应头
	Info UnionRankInfo           `json:"body"` // 排队信息
}

// ctx_map 全局上下文映射
// 存储任务ID和对应的上下文控制器，用于任务管理
var ctx_map = sync.Map{}

// routine_controller 协程控制器
// 用于控制和取消正在运行的协程
type routine_controller struct {
	ctx    context.Context    // 上下文
	cancel context.CancelFunc // 取消函数
}

// StressTestBody 压力测试请求体
// 启动压力测试时的请求参数（兼容旧版本字段名）
type StressTestBody struct {
	UserID          string `json:"user_id"`          // 用户ID前缀
	Total           uint64 `json:"total"`            // 总客户端数量
	HoldTime        int    `json:"holdtime"`         // 保持时间（秒）
	TaskID          string `json:"task_id"`          // 任务唯一标识
	Biz             uint64 `json:"biz"`              // 业务类型
	GID             uint64 `json:"gid"`              // 游戏ID
	SPConcurrency   uint64 `json:"sp_concurrency"`   // 特殊并发数
	PerformanceMode uint64 `json:"performance_mode"` // 性能模式
	Env             string `json:"env"`              // 运行环境（sit/uat/pro）
	IsQuickOut      bool   `json:"is_quickout"`      // 是否快速退出
	IsStreaming     bool   `json:"is_streaming"`     // 是否启用流式传输
	DelayExit       int    `json:"delay_exit"`       // 延迟退出时间
	RSetID          int    `json:"rset_id"`          // 资源集ID
	IsAutoRegister  bool   `json:"is_auto_regist"`   // 是否自动注册
	StartUUID       uint64 `json:"start_uuid"`       // 起始UUID
	IsDelKey        bool   `json:"is_del_key"`       // 是否删除Redis键
	IsTrylock       bool   `json:"is_trylock"`       // 是否启用资源预锁定，默认为false
}

// TaskStartParams 任务启动参数结构体
// 新版本的任务启动参数，字段命名更加规范
type TaskStartParams struct {
	// 基础任务信息
	UserID       string `json:"user_id"`       // 发起用户唯一标识
	TaskID       string `json:"task_id"`       // 任务唯一标识符
	BusinessType uint64 `json:"business_type"` // 业务类型分类编码
	GroupID      uint64 `json:"group_id"`      // 任务所属资源组/集群ID

	// 资源控制参数
	TotalInstances  uint64 `json:"total_instances"`   // 需要启动的总实例数量
	HoldDurationSec int    `json:"hold_duration_sec"` // 资源保持时间（秒）
	DelayExitSec    int    `json:"delay_exit_sec"`    // 结束延迟等待时间（秒）

	// 性能配置
	MaxConcurrency  uint64 `json:"max_concurrency"`   // 最大并发处理数
	PerformanceMode uint64 `json:"performance_mode"`  // 性能模式选择标记
	ServicePoolSize uint64 `json:"service_pool_size"` // 服务池并发容量

	// 环境控制
	Environment   string `json:"environment"`     // 运行环境标识 (sit/uat/pro)
	ResourceSetID int    `json:"resource_set_id"` // 关联资源集合ID

	// 功能开关
	QuickTermination bool `json:"quick_termination"`  // 是否启用快速终止
	StreamingMode    bool `json:"streaming_mode"`     // 是否启用流式处理模式
	AutoRegistration bool `json:"auto_registration"`  // 是否自动注册资源
	DeleteKeyOnExit  bool `json:"delete_key_on_exit"` // 退出时删除关联密钥

	StartUUID uint64 `json:"start_uuid"` // 启动批次唯一标识
}
